﻿/* author: Mariana Horita
   mariana.horita@gmail.com
   file: Form1.cs*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace K_Vizinhos
{
    public partial class Form1 : Form
    {

        private List<myRadioButton> lrdbClasse = new List<myRadioButton>();
        private List<Classe> lClasse = new List<Classe>();
        private Classe currentClass;
        private List<Ponto> pontos = new List<Ponto>();
        private int eixoX = 300;
        private int eixoY = 50;
        private int dist = 25;
        private int max;
        private int min;
        private myButton btCorDefault = new myButton();
        private List<Label> xLabel = new List<Label>();
        private List<Label> yLabel = new List<Label>();

        private Bitmap graphGrid;
        private Bitmap GraphGrid
        {
            get
            {
                if (graphGrid == null)
                    graphGrid = DrawGraphGrid();
                return graphGrid;
            }
        }

        private int largPonto = 4;

        public Form1()
        {
            InitializeComponent();
            pnlGrafico.BackColor = Color.White;

            pnlGrafico.BackgroundImage = GraphGrid;
            InicializaForm(100, 0);

        }

        private Bitmap DrawGraphGrid()
        {
            Bitmap btmp = new Bitmap(pnlGrafico.Width, pnlGrafico.Height);

            for (int i = 10; i < 350; i++)
            {
                // eixo vertical
                btmp.SetPixel(eixoY + 1, i, Color.Black);
                btmp.SetPixel(eixoY, i, Color.Black);

                // eixo horizontal
                btmp.SetPixel(i, eixoX, Color.Black);
                btmp.SetPixel(i, eixoX + 1, Color.Black);

            }

            for (int i = eixoY; i < eixoX; i += dist)
            {

                Label lbl = new Label();
                
                lbl.BackColor = Color.Transparent;
                lbl.Location = new Point(15, i - 5);
                lbl.Size = new System.Drawing.Size(30, 20);
                pnlGrafico.Controls.Add(lbl);

                xLabel.Add(lbl);
                
                for (int j = eixoY - 6; j < 350; j++)
                {
                    btmp.SetPixel(j, i, Color.Gray);
                }
            }

            
            for (int i = eixoX; i > eixoY; i -= dist)
            {

                Label lbl = new Label();
                lbl.BackColor = Color.Transparent;
                lbl.Location = new Point(i - 10, 315);
                lbl.Size = new System.Drawing.Size(30, 20);
                pnlGrafico.Controls.Add(lbl);

                yLabel.Add(lbl);

                for (int j = 10; j < eixoX + 6; j++)
                {
                    btmp.SetPixel(i, j, Color.Gray);
                }
            }

            return btmp;
        }


        private void InicializaForm(int max, int min)
        {   
            this.max = max;
            this.min = min;
            pnlInfo.Controls.Clear();

            pnlInfo.Controls.Add(nudK);
            txtPontos.Text = "";
            lrdbClasse = new List<myRadioButton>();
            
            // 380 x 356
           
            int escala = (max - min) / 10;
            int val = max;
            

            foreach (Label lbl in xLabel)
            {
                lbl.Text = val.ToString();
                val -= escala;
            }


            val = max;
            
            foreach (Label lbl in yLabel)
            {
                lbl.Text = val.ToString();
                val -= escala;
            }

            


            myRadioButton mrb = new myRadioButton();
            mrb.Text = "K-Vizinhos";
            mrb.Checked = true;
            mrb.Location = new Point(30, 5);
            lrdbClasse.Add(mrb);
            pnlInfo.Controls.Add(mrb);

            
            btCorDefault.FlatStyle = FlatStyle.Popup;
            btCorDefault.Size = new System.Drawing.Size(20, 20);
            btCorDefault.Location = new Point(5, 5);
            btCorDefault.Enabled = false;
            btCorDefault.BackColor = Color.Empty;
            pnlInfo.Controls.Add(btCorDefault);

        }

        private void sairToolStripMenuItem_Click(object sender, EventArgs e)
        {
            /*
            DialogResult dr = MessageBox.Show("Deseja Salvar Alterações?", "", MessageBoxButtons.YesNoCancel);
            switch (dr)
            {
                case DialogResult.Yes:
                     SaveFile();
                     this.Close();
                     break;
                case DialogResult.No:
                     this.Close();
                     break;
            }*/
            this.Close();
            
        }

        private void abrirToolStripMenuItem_Click(object sender, EventArgs e)
        {

            DialogResult dr = MessageBox.Show("Deseja Salvar Alterações?", "", MessageBoxButtons.YesNoCancel);
            switch (dr)
            {
                case DialogResult.Yes:
                case DialogResult.No:
                    if (dr == DialogResult.Yes)
                    {
                        saveFileDialog1.ShowDialog();
                        SaveFile();
                    }
                    
                    if (openFileDialog1.ShowDialog() == DialogResult.OK)
                    {
                        StreamReader sr = new StreamReader(openFileDialog1.FileName);

                        this.Text = openFileDialog1.FileName;

                        Graphics g = pnlGrafico.CreateGraphics();
                        g.Clear(Color.White);
                        g.Save();
                        g.Dispose();

                        try
                        {
                            pontos = new List<Ponto>();
                            lClasse = new List<Classe>();

                            #region Ler arquivo
                            while (!sr.EndOfStream)
                            {
                                string[] linha = sr.ReadLine().Split(',');
                                pontos.Add(new Ponto(Convert.ToInt32(linha[0]), Convert.ToInt32(linha[1]), linha[2]));

                                if ((from m in lClasse where m.Nome == linha[2] select m).SingleOrDefault() == null)
                                {
                                    lClasse.Add(new Classe(linha[2], lClasse.Count + 1));
                                }

                            }
                            

                            sr.Close();
                            #endregion

                            InicializaForm(Math.Max((from m in pontos orderby m.X descending select m.X).First(), (from m in pontos orderby m.Y descending select m.Y).First()), 0);

                            foreach (Ponto p in pontos)
                            {
                                txtPontos.Text += p.Classe + " (" + p.X + ", " + p.Y + ")\r\n";
                            }

                            foreach (Classe c in lClasse)
                            {

                                myButton btCor = new myButton();
                                btCor.FlatStyle = FlatStyle.Popup;
                                btCor.Size = new System.Drawing.Size(20, 20);
                                btCor.Click += new EventHandler(btCor_Click);
                                btCor.objClasse = c;
                                btCor.Location = new Point(5, btCor.objClasse.Id * 30);
                                btCor.BackColor = c.Cor;
                                pnlInfo.Controls.Add(btCor);

                                myRadioButton rbt = new myRadioButton();
                                rbt.Text = c.Nome;
                                rbt.objClasse = c;
                                rbt.CheckedChanged += new EventHandler(rbt_CheckedChanged);
                                rbt.Location = new Point(30, rbt.objClasse.Id * 30);

                                lrdbClasse.Add(rbt);

                                pnlInfo.Controls.Add(rbt);

                                currentClass = c;
                                reDrawnPoints((from m in pontos where m.Classe == c.Nome select m).ToArray(), c.Cor);
                            }
                            
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show("Arquivo em formato inválido");
                        }
                    }
                    break;
            }
        }

        private void adicionarToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AddClasse f = new AddClasse((from m in lClasse select m.Nome).ToArray());
            if (DialogResult.OK == f.ShowDialog())
            {   
                Classe c = new Classe(f.Nome, lClasse.Count + 1, f.Cor);
                myButton btCor = new myButton();
                btCor.FlatStyle = FlatStyle.Popup;
                btCor.Size = new System.Drawing.Size(20, 20);
                btCor.Click += new EventHandler(btCor_Click);
                btCor.objClasse = c;
                btCor.Location = new Point(5, btCor.objClasse.Id * 30 );
                btCor.BackColor = c.Cor;
                pnlInfo.Controls.Add(btCor);
                lClasse.Add(c);
                myRadioButton rbt = new myRadioButton();
                rbt.Text = c.Nome;
                rbt.objClasse = c;
                rbt.CheckedChanged += new EventHandler(rbt_CheckedChanged);
                rbt.Location = new Point(30, rbt.objClasse.Id * 30 );

                (from m in lrdbClasse
                 where m.Checked = false
                 select m).ToArray();

                lrdbClasse.Add(rbt);
                rbt.Checked = true;
                pnlInfo.Controls.Add(rbt);

                currentClass = c;

            }
        }

        void btCor_Click(object sender, EventArgs e)
        {
            if (colorDialog1.ShowDialog() == DialogResult.OK)
            {
                myButton btCor = (myButton)sender;
                btCor.BackColor = colorDialog1.Color;
                btCor.objClasse.Cor = colorDialog1.Color;

                reDrawnPoints((from m in pontos
                               where m.Classe == btCor.objClasse.Nome
                               select m).ToArray(), btCor.objClasse.Cor);

            }
        }

        void rbt_CheckedChanged(object sender, EventArgs e)
        {
            btCorDefault.BackColor = Color.Empty;
            myRadioButton rbt = (myRadioButton)sender;
            currentClass = rbt.objClasse;
        }

        private void pnlGrafico_Click(object sender, EventArgs e)
        {
            if (PointX(((MouseEventArgs)e).Location.X) > min && PointX(((MouseEventArgs)e).Location.X) < max
                && PointY(((MouseEventArgs)e).Location.Y) > min && PointY(((MouseEventArgs)e).Location.Y) < max)
            {
                if (currentClass != null)
                {

                    Graphics g = pnlGrafico.CreateGraphics();
                    Point p = ((MouseEventArgs)e).Location;
                    p.X = p.X - largPonto / 2;
                    p.Y = p.Y - largPonto / 2;

                    g.FillEllipse(new SolidBrush(currentClass.Cor), new Rectangle(p, new Size(largPonto, largPonto)));

                    Ponto ponto = new Ponto(PointX(((MouseEventArgs)e).Location.X), PointY(((MouseEventArgs)e).Location.Y), currentClass.Nome);
                    pontos.Add(ponto);

                    txtPontos.Text += currentClass.Nome + " (" + PointX(((MouseEventArgs)e).Location.X) + ", " + PointY(((MouseEventArgs)e).Location.Y) + ")\r\n";

                    g.Save();
                    g.Dispose();
                }
            }
        }


        private void reDrawnPoints(Ponto [] pontos, Color cor)
        {
            Graphics g = pnlGrafico.CreateGraphics();
            foreach (Ponto p in pontos)
            {
                Point ponto = new Point(LocationX(p.X) - largPonto / 2, LocationY(p.Y) - largPonto / 2);
                g.FillEllipse(new SolidBrush(cor), new Rectangle(ponto, new Size(largPonto, largPonto)));

            }
            g.Save();
            g.Dispose();
        }

        private void novoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DialogResult dr = MessageBox.Show("Deseja Salvar Alterações?", "", MessageBoxButtons.YesNoCancel);
            if (dr == DialogResult.Yes)
            {
                pontos = new List<Ponto>();
                lClasse = new List<Classe>();
                saveFileDialog1.ShowDialog();
                SaveFile();
                Graphics g = pnlGrafico.CreateGraphics();
                g.Clear(Color.White);
                g.DrawImage(GraphGrid, new Point(0, 0));
                g.Save();
                g.Dispose();
                                
                InicializaForm(100,0);
                
            }
            else if (dr == DialogResult.No)
            {
                this.Text = "K-Vizinhos";

                pontos = new List<Ponto>();
                lClasse = new List<Classe>();

                Graphics g = pnlGrafico.CreateGraphics();
                g.Clear(Color.White);
                
                g.DrawImage(GraphGrid, new Point(0, 0));
                g.Save();
                g.Dispose();
                pnlGrafico.BackgroundImage = GraphGrid;
                InicializaForm(100,0);
            }
            
        }

        private void SaveFile()
        {
            if (saveFileDialog1.ShowDialog() == DialogResult.OK)
            {
                StreamWriter sw = new StreamWriter(saveFileDialog1.FileName);

                foreach (Ponto p in pontos)
                {
                    sw.WriteLine(p.X + "," + p.Y + "," + p.Classe);
                }
                sw.Close();
            }
        }

        private void pnlGrafico_MouseMove(object sender, MouseEventArgs e)
        {   
            if (PointX(e.Location.X) >= min && PointX(e.Location.X) <= max && PointY(e.Location.Y) >= min && PointY(e.Location.Y) <= max)
            {
                lblLocation.Text = "(" + PointX(e.Location.X) + "," + PointY(e.Location.Y) + ")";


                if (lrdbClasse.First().Checked && lClasse.Count > 1)
                {
                    // Calculo a distancia para cada ponto
                    foreach (Ponto p in pontos)
                    {
                        p.Dist = CalcDist(new Point( PointX( e.Location.X), PointY(e.Location.Y)), p);
                    }

                    // ordeno os pontos pela distancia 
                    List<Ponto> pts = (from m in pontos
                                       orderby m.Dist ascending
                                       select m).ToList();
                    if (pts.Count > nudK.Value)
                    {
                        pts.RemoveRange(Convert.ToInt32(nudK.Value), Convert.ToInt32(pontos.Count - nudK.Value));

                    }
                    var classes = from m in pts
                                  group m by m.Classe into d
                                  orderby d.Count() descending
                                  select new {classe = d.Key, count = d.Count()};


                    /* Pensar aquiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii */
                    var empate = (from m in classes where m.count == classes.First().count select m).ToArray();
                    if (empate.Count() > 1)
                    {
                        foreach (var c in empate)
                        {

                        }
                    }
                    


                    Classe cl = (from m in lClasse
                                 where m.Nome == classes.First().classe
                                 select m).SingleOrDefault();

                    if (cl != null)
                    {
                        btCorDefault.BackColor = cl.Cor;
                        currentClass = cl;
                    }
                     
                }
                
            }
            foreach (Classe c in lClasse)
            {
                reDrawnPoints((from m in pontos where m.Classe == c.Nome select m).ToArray(), c.Cor);
            }
        }

        private int LocationX(int x)
        {
            return x * (eixoX - eixoY) / max + eixoY;
        }

        private int PointX(int x)
        {
            return Convert.ToInt32((x - eixoY) * max / Convert.ToDouble(eixoX - eixoY));
        }

        private int LocationY(int y)
        {
            return -1 *( y * (eixoX - eixoY) / max - eixoX);
        }

        private int PointY(int y)
        {
            return Convert.ToInt32((eixoX - y) * max / Convert.ToDouble(eixoX - eixoY));
        }

        private double CalcDist(Point p, Ponto ponto)
        {
            return Math.Sqrt(Math.Pow(p.X - ponto.X, 2) + Math.Pow(p.Y - ponto.Y, 2));
        }

        private void salvarToolStripMenuItem_Click(object sender, EventArgs e)
        {  
            SaveFile();
        }

        private void adicionarDadosAleatóriosToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (lClasse.Count == 0)
            {
                MessageBox.Show("Só é possível adicionar dados aleatórios após a definição de classes");
            }
            else
            {
                AddRandomData f = new AddRandomData();
                if (f.ShowDialog() == DialogResult.OK)
                {
                    Random rd = new Random();
                    if (f.randomData)
                    {
                        for (int i = 0; i < f.quantidade; i++)
                        {
                            pontos.Add(new Ponto(rd.Next(min, max), rd.Next(min, max), lClasse.ElementAt(rd.Next(lClasse.Count)).Nome));
                        }
                    }
                    else
                    {
                        int q = f.quantidade / lClasse.Count;
                        foreach (Classe c in lClasse)
                        {
                            for (int i = 0; i < q; i++)
                            {
                                pontos.Add(new Ponto(rd.Next(min, max), rd.Next(min, max), c.Nome));
                            }
                        }
                    }

                    foreach (Classe c in lClasse)
                    {
                        reDrawnPoints((from m in pontos where m.Classe == c.Nome select m).ToArray(), c.Cor);
                    }

                    foreach (Ponto p in pontos)
                    {
                        txtPontos.Text += p.Classe + " (" + p.X + ", " + p.Y + ")\r\n";
                    }

                }
            }
        }

        private void AjudaToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Ajuda aj = new Ajuda();
            aj.ShowDialog();
        }


        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            DialogResult dr = MessageBox.Show("Deseja Salvar Alterações?", "", MessageBoxButtons.YesNoCancel);
            switch (dr)
            {
                case DialogResult.Yes:
                    SaveFile();
                    break;
                case DialogResult.No:
                    break;
                case DialogResult.Cancel:
                    e.Cancel = true;
                    break;
            }
        }

        

    }
}
